/**
 * Copyright 2008 Adam Ruggles.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package kiff.service.impl;

import java.util.Date;
import java.util.List;

import kiff.dao.CoreDAO;
import kiff.entity.CoreEntity;
import kiff.entity.TrackAware;
import kiff.entity.UpdateAware;
import kiff.entity.User;
import kiff.exception.DataLayerException;
import kiff.exception.ServiceLayerException;
import kiff.service.CoreService;

import com.google.inject.Inject;

/**
 * Abstract Service bean.  This service is a default implementation of the CoreService interface.  All Service
 * Beans are recommended to extend from this class.
 * @author Adam
 * @version $Id: AbstractService.java 73 2008-12-02 06:28:25Z a.ruggles $
 * @param <T> Class Type that extends ICoreEntity.
 */
@kiff.util.transaction.annotation.Transactional
public abstract class AbstractService <T extends CoreEntity<?>> implements CoreService<T> {
    /**
     * Data Access Object, used to access data from the data/persistence layer.
     */
    protected CoreDAO<T> dao;

    /**
     * {@inheritDoc}
     * @see kiff.service.CoreService#find(java.lang.Object)
     */
	public T find(final Object id) throws ServiceLayerException {
    	try {
            return dao.findById(id);
        } catch (DataLayerException dataLayerException) {
            throw new ServiceLayerException(dataLayerException);
        }
	}

	/**
	 * {@inheritDoc}
	 * @see kiff.service.CoreService#findAll()
	 */
	public List<T> findAll() throws ServiceLayerException {
		try {
            return dao.findAll();
        } catch (DataLayerException dataLayerException) {
            throw new ServiceLayerException(dataLayerException);
        }
	}

	/**
	 * {@inheritDoc}
	 * @see kiff.service.CoreService#insert(java.lang.Object, kiff.entity.User)
	 */
	public void insert(final T entity, final User user) throws ServiceLayerException {
		try {
			if (entity instanceof TrackAware) {
				Date timestamp = new Date();
				TrackAware track = ((TrackAware) entity);
				track.setCreator(user);
				track.setCreated(timestamp);
				track.setModified(timestamp);
			}
            dao.insert(entity);
        } catch (DataLayerException dataLayerException) {
            throw new ServiceLayerException(dataLayerException);
        }
	}

	/**
	 * {@inheritDoc}
	 * @see kiff.service.CoreService#refresh(java.lang.Object)
	 */
	public void refresh(final T entity) throws ServiceLayerException {
		try {
			dao.refresh(entity);
		} catch (DataLayerException dataLayerException) {
            throw new ServiceLayerException(dataLayerException);
        }
	}

	/**
	 * {@inheritDoc}
	 * @see kiff.service.CoreService#remove(java.lang.Object, kiff.entity.User)
	 */
	public void remove(final T entity, final User user) throws ServiceLayerException {
		try {
			T entityToRemove = dao.loadById(entity.getId());
            dao.delete(entityToRemove);
		} catch (DataLayerException dataLayerException) {
            throw new ServiceLayerException(dataLayerException);
        }
	}

	/**
	 * Sets the dao.
	 * @param dao the dao to set.
	 */
	@Inject(optional = true)
	public void setDao(final CoreDAO<T> dao) {
		this.dao = dao;
	}

	/**
	 * {@inheritDoc}
	 * @see kiff.service.CoreService#update(java.lang.Object, kiff.entity.User)
	 */
	@SuppressWarnings("unchecked")
	public T update(final T entity, final User user) throws ServiceLayerException {
		try {
			if (entity instanceof TrackAware) {
            	((TrackAware) entity).setModified(new Date());
            }
			if (entity instanceof UpdateAware) {
				T persistent = dao.loadById(entity.getId());
				((UpdateAware) persistent).update(entity);
				return dao.update(persistent);
			}
            return dao.update(entity);
		} catch (DataLayerException dataLayerException) {
            throw new ServiceLayerException(dataLayerException);
        }
	}

}
